package cn.iocoder.yudao.module.system.service.gugu;

import cn.iocoder.yudao.module.system.controller.admin.gugu.vo.CollegeRecommendItemVO;
import cn.iocoder.yudao.module.system.controller.admin.gugu.vo.CollegeRecommendReqVO;
import cn.iocoder.yudao.module.system.controller.admin.gugu.vo.CollegeRecommendRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.gugu.*;
import cn.iocoder.yudao.module.system.dal.dataobject.college.CollegeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.collegeenrollmentplan.CollegeEnrollmentPlanDO;
import cn.iocoder.yudao.module.system.dal.mysql.gugu.*;
import cn.iocoder.yudao.module.system.dal.mysql.college.CollegeMapper;
import cn.iocoder.yudao.module.system.dal.mysql.collegeenrollmentplan.CollegeEnrollmentPlanMapper;
import cn.iocoder.yudao.module.system.util.SubjectSelectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.util.gugu.BatchQueryOptimizer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 高校推荐服务实现类
 *
 * @author 芋道源码
 */
@Service
@Slf4j
public class CollegeRecommendationServiceImpl implements CollegeRecommendationService {

    @Resource
    private CollegeRecommendationMapper collegeRecommendationMapper;

    @Resource
    private MajorAdmissionMapper majorAdmissionMapper;

    @Resource
    private CollegeMapper collegeMapper;

    @Resource
    private CollegeEnrollmentPlanMapper collegeEnrollmentPlanMapper;

    @Resource
    private ScoreSegmentMapper scoreSegmentMapper;

    @Resource
    private CeeMajorMapper ceeMajorMapper;

    /**
     * 录取概率计算线程池
     */
    private final ExecutorService probabilityCalculationExecutor =
        new ThreadPoolExecutor(4, 8, 60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000),
            r -> new Thread(r, "probability-calc-" + System.currentTimeMillis()),
            new ThreadPoolExecutor.CallerRunsPolicy());

    /**
     * 录取概率缓存 - 缓存键格式: userRank:schoolUuid:majorName:province:year:examType
     */
    private final Map<String, Double> probabilityCache = new ConcurrentHashMap<>();

    /**
     * 批量数据缓存 - 避免重复查询
     */
    private final Map<String, List<MajorAdmissionDO>> batchDataCache = new ConcurrentHashMap<>();

    @Override
    public CollegeRecommendRespVO recommendColleges(CollegeRecommendReqVO reqVO) {
        return recommendColleges(reqVO, null);
    }

    @Override
    public CollegeRecommendRespVO recommendColleges(CollegeRecommendReqVO reqVO, Long userId) {
        log.info("开始智能推荐大学，用户ID：{}，省份：{}，分数：{}，位次：{}", 
                userId, reqVO.getProvince(), reqVO.getScore(), reqVO.getRanks());

        long startTime = System.currentTimeMillis();

        try {
            // 1. 参数预处理
            Integer userRank = reqVO.getRanks();
            if (userRank == null) {
                // 如果没有提供位次，根据分数和一分一段表计算位次
                userRank = calculateRankByScore(reqVO.getScore(), reqVO.getProvince(), reqVO.getYear(), reqVO.getClassify());
            }

            // 2. 根据选科要求筛选可报考的专业
            List<String> subjectList = Arrays.asList(reqVO.getSubjects().split(","));
            List<MajorAdmissionDO> candidateMajors = filterMajorsBySubjects(subjectList, reqVO.getProvince(), 
                    reqVO.getYear(), reqVO.getClassify(), reqVO.getBatch());

            // 3. 智能分页处理，优先计算最相关的专业
            log.info("开始智能分页处理，候选专业数量：{}", candidateMajors.size());

            // 根据页面大小和页码，智能选择要处理的专业
            List<MajorAdmissionDO> prioritizedMajors = prioritizeMajorsForProcessing(
                candidateMajors, userRank, reqVO.getPageNum(), reqVO.getPageSize());

            log.info("优先处理专业数量：{}", prioritizedMajors.size());

            Map<String, Double> probabilityResults = batchCalculateAdmissionProbability(
                prioritizedMajors, userRank, reqVO.getProvince(), reqVO.getYear(), reqVO.getClassify());

            log.info("批量计算完成，获得概率结果：{} 个", probabilityResults.size());

            // 4. 构建推荐项列表（基于优先处理的专业）
            List<CollegeRecommendItemVO> allRecommendations = new ArrayList<>();
            int chongCount = 0, wentuoCount = 0, baodiCount = 0;

            for (MajorAdmissionDO major : prioritizedMajors) {
                try {
                    String key = major.getSchoolUuid() + ":" + major.getMajorName();
                    Double probability = probabilityResults.get(key);

                    if (probability == null || probability < 10) {
                        continue; // 概率过低，不推荐
                    }

                    // 判断推荐类型
                    String type = determineRecommendationType(probability);

                    // 构建推荐项
                    CollegeRecommendItemVO item = buildRecommendationItem(major, probability, type, reqVO);
                    if (item != null) {
                        allRecommendations.add(item);

                        // 统计各类型数量
                        switch (type) {
                            case "CHONG":
                                chongCount++;
                                break;
                            case "WENTUO":
                                wentuoCount++;
                                break;
                            case "BAODI":
                                baodiCount++;
                                break;
                        }
                    }
                } catch (Exception e) {
                    log.warn("处理专业推荐时发生异常：{}，专业：{}", e.getMessage(), major.getMajorName());
                }
            }

            // 4. 应用偏好过滤
            if (reqVO.getPreferences() != null) {
                allRecommendations = applyPreferences(allRecommendations, reqVO.getPreferences());
            }

            // 5. 按推荐类型和概率排序
            allRecommendations.sort((a, b) -> {
                // 先按类型排序：BAODI > WENTUO > CHONG
                int typeCompare = getTypeOrder(a.getType()) - getTypeOrder(b.getType());
                if (typeCompare != 0) {
                    return typeCompare;
                }
                // 同类型按概率降序
                return b.getEnrollProbability().compareTo(a.getEnrollProbability());
            });

            // 6. 分页处理
            int total = allRecommendations.size();
            int startIndex = (reqVO.getPageNum() - 1) * reqVO.getPageSize();
            int endIndex = Math.min(startIndex + reqVO.getPageSize(), total);
            List<CollegeRecommendItemVO> pageList = allRecommendations.subList(startIndex, endIndex);

            // 7. 保存推荐记录（如果有用户ID）
            if (userId != null) {
                saveRecommendationRecords(userId, pageList, reqVO);
            }

            // 8. 构建响应结果
            CollegeRecommendRespVO respVO = buildResponse(pageList, reqVO, total, chongCount, wentuoCount, baodiCount, userRank);

            long endTime = System.currentTimeMillis();
            log.info("智能推荐完成，耗时：{}ms，推荐院校总数：{}", endTime - startTime, total);

            return respVO;

        } catch (Exception e) {
            log.error("智能推荐大学发生异常", e);
            throw new RuntimeException("推荐服务异常：" + e.getMessage());
        }
    }

    @Override
    public Double calculateAdmissionProbability(Integer userRank, String schoolUuid, String majorName, 
                                              String province, Integer year, String examType) {
        try {
            // 1. 获取近3年该专业的录取数据
            List<MajorAdmissionDO> historyData = majorAdmissionMapper.selectBySchoolAndMajor(
                    schoolUuid, majorName, province, Arrays.asList(year - 2, year - 1, year));

            if (historyData.isEmpty()) {
                return null;
            }

            // 2. 获取招生计划数据
            List<CollegeEnrollmentPlanDO> planData = collegeEnrollmentPlanMapper.selectBySchoolAndMajor(
                    schoolUuid, majorName, province, Arrays.asList(year - 2, year - 1, year));

            // 3. 计算加权平均位次（考虑招生计划变化）
            List<Integer> adjustedRanks = new ArrayList<>();
            double[] weights = {0.5, 0.3, 0.2}; // 近3年权重

            for (int i = 0; i < historyData.size() && i < weights.length; i++) {
                MajorAdmissionDO data = historyData.get(i);
                if (data.getLowestSection() != null && !data.getLowestSection().isEmpty()) {
                    try {
                        int historicalRank = Integer.parseInt(data.getLowestSection());
                        
                        // 根据招生计划变化调整历史位次
                        int adjustedRank = adjustRankByPlanChange(historicalRank, data, planData, year);
                        adjustedRanks.add(adjustedRank);
                    } catch (NumberFormatException e) {
                        log.warn("位次数据格式错误：{}", data.getLowestSection());
                    }
                }
            }

            if (adjustedRanks.isEmpty()) {
                return null;
            }

            // 4. 计算加权平均位次
            double weightedAvgRank = 0;
            double totalWeight = 0;
            for (int i = 0; i < adjustedRanks.size() && i < weights.length; i++) {
                weightedAvgRank += adjustedRanks.get(i) * weights[i];
                totalWeight += weights[i];
            }
            weightedAvgRank /= totalWeight;

            // 5. 计算标准差
            double variance = 0;
            for (int rank : adjustedRanks) {
                variance += Math.pow(rank - weightedAvgRank, 2);
            }
            variance /= adjustedRanks.size();
            double stdDev = Math.sqrt(variance);

            // 6. 使用正态分布计算概率
            double zScore = (userRank - weightedAvgRank) / Math.max(stdDev, 1000); // 避免除零
            double baseProbability = normalCDF(-zScore) * 100; // 转换为百分比

            // 7. 应用修正因子
            double finalProbability = baseProbability;

            // 专业热度修正
            if (isHotMajor(majorName)) {
                finalProbability *= 0.85; // 热门专业降低15%概率
            }

            // 确保概率在0-100范围内
            return Math.max(0, Math.min(100, finalProbability));

        } catch (Exception e) {
            log.error("计算录取概率时发生异常：{}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 批量计算录取概率（优化版本）
     * 使用批量查询和多线程处理，显著提升性能
     *
     * @param candidateMajors 候选专业列表
     * @param userRank 用户位次
     * @param province 省份
     * @param year 年份
     * @param examType 考试类型
     * @return 录取概率结果 Map，键为 "schoolUuid:majorName"
     */
    private Map<String, Double> batchCalculateAdmissionProbability(
            List<MajorAdmissionDO> candidateMajors, Integer userRank,
            String province, Integer year, String examType) {

        if (candidateMajors == null || candidateMajors.isEmpty()) {
            return new HashMap<>();
        }

        long startTime = System.currentTimeMillis();
        Map<String, Double> results = new ConcurrentHashMap<>();

        try {
            // 1. 提取所有需要查询的学校UUID和专业名称
            List<String> schoolUuids = candidateMajors.stream()
                .map(MajorAdmissionDO::getSchoolUuid)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

            List<String> majorNames = candidateMajors.stream()
                .map(MajorAdmissionDO::getMajorName)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

            log.info("批量查询参数 - 学校数量：{}，专业数量：{}", schoolUuids.size(), majorNames.size());

            // 2. 使用优化器智能选择查询策略
            BatchQueryOptimizer.QueryStrategy strategy = BatchQueryOptimizer.determineQueryStrategy(
                schoolUuids.size(), majorNames.size(), candidateMajors.size());

            List<Integer> years = Arrays.asList(year - 2, year - 1, year);
            List<MajorAdmissionDO> allHistoryData = new ArrayList<>();

            long queryStartTime = System.currentTimeMillis();
            boolean querySuccess = false;

            try {
                switch (strategy) {
                    case ULTRA_SIMPLE:
                        allHistoryData = performUltraSimpleQuery(schoolUuids, majorNames, years, examType, province);
                        break;
                    case SUPER_BATCH:
                        allHistoryData = performSuperBatchQuery(schoolUuids, majorNames, years, examType, province);
                        break;
                    case NORMAL_BATCH:
                        allHistoryData = performNormalBatchQuery(schoolUuids, majorNames, years, examType, province);
                        break;
                    default:
                        allHistoryData = performFallbackQuery(schoolUuids, majorNames, years.get(0), examType, province);
                        break;
                }
                querySuccess = true;
            } catch (Exception e) {
                log.error("查询策略 {} 执行失败，尝试降级", strategy, e);
                allHistoryData = performFallbackQuery(schoolUuids, majorNames, years.get(0), examType, province);
            } finally {
                long queryEndTime = System.currentTimeMillis();
                BatchQueryOptimizer.recordQueryExecution(strategy, queryEndTime - queryStartTime, querySuccess);
            }

            log.info("批量查询录取数据完成，获得历史数据：{} 条", allHistoryData.size());

            // 保持数据完整性，不进行截断，通过其他方式优化性能
            log.info("保持历史数据完整性，数据量：{} 条", allHistoryData.size());

            // 3. 批量查询招生计划数据（简化处理）
            List<CollegeEnrollmentPlanDO> allPlanData = new ArrayList<>();
            try {
                // 查询所有相关年份的招生计划数据，保持完整性
                List<String> schoolNames = candidateMajors.stream()
                    .map(MajorAdmissionDO::getSchoolName)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList());

                // 查询所有年份的招生计划数据
                for (Integer queryYear : years) {
                    try {
                        List<CollegeEnrollmentPlanDO> yearPlanData = collegeEnrollmentPlanMapper
                            .selectExistingEnrollmentPlansWithBracketHandling(schoolNames, majorNames, province, queryYear);
                        allPlanData.addAll(yearPlanData);
                    } catch (Exception e) {
                        log.warn("查询{}年招生计划数据失败：{}", queryYear, e.getMessage());
                    }
                }


                log.info("批量查询招生计划数据完成，获得计划数据：{} 条", allPlanData.size());
            } catch (Exception e) {
                log.warn("查询招生计划数据失败：{}", e.getMessage());
            }

            // 4. 使用迭代式分组，避免递归栈溢出
            Map<String, List<MajorAdmissionDO>> groupedHistoryData = iterativeGroupHistoryData(allHistoryData);

            // 5. 使用迭代式分组招生计划数据
            Map<String, List<CollegeEnrollmentPlanDO>> groupedPlanData = iterativeGroupPlanData(allPlanData);

            log.info("数据分组完成，历史数据组数：{}，计划数据组数：{}",
                groupedHistoryData.size(), groupedPlanData.size());

            // 6. 保持候选专业完整性，不进行任何截断或筛选
            List<MajorAdmissionDO> processableMajors = candidateMajors;
            log.info("保持候选专业完整性，专业数量：{} 个", candidateMajors.size());

            // 7. 为了确保数据准确性，优先使用单线程处理，避免并发问题
            log.info("使用单线程迭代式计算录取概率，确保数据准确性，专业数量：{}", processableMajors.size());
            results = calculateProbabilityWithIterativeMethod(processableMajors, userRank,
                groupedHistoryData, groupedPlanData);

        } catch (Exception e) {
            log.error("批量计算录取概率时发生异常", e);
        }

        long endTime = System.currentTimeMillis();
        log.info("批量计算录取概率完成，耗时：{}ms，结果数量：{}",
            endTime - startTime, results.size());

        // 内存监控和统计
        BatchQueryOptimizer.suggestGarbageCollection();

        // 定期输出统计信息
        if (System.currentTimeMillis() % 300000 < 1000) { // 大约每5分钟输出一次
            BatchQueryOptimizer.printStats();
        }

        return results;
    }

    /**
     * 多线程计算录取概率（优化版，避免栈溢出）
     */
    private Map<String, Double> calculateProbabilityWithMultiThread(
            List<MajorAdmissionDO> candidateMajors, Integer userRank,
            Map<String, List<MajorAdmissionDO>> groupedHistoryData,
            Map<String, List<CollegeEnrollmentPlanDO>> groupedPlanData) {

        Map<String, Double> results = new ConcurrentHashMap<>();

        // 减小批次大小，避免单个任务处理过多数据
        int batchSize = 10; // 进一步减小批次
        List<List<MajorAdmissionDO>> batches = new ArrayList<>();
        for (int i = 0; i < candidateMajors.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, candidateMajors.size());
            batches.add(candidateMajors.subList(i, endIndex));
        }

        // 限制并发任务数量
        final int MAX_CONCURRENT_TASKS = 4;
        List<CompletableFuture<Void>> futures = new ArrayList<>();

        for (int i = 0; i < batches.size(); i++) {
            List<MajorAdmissionDO> batch = batches.get(i);
            final int batchIndex = i;

            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try {
                    for (MajorAdmissionDO major : batch) {
                        try {
                            String key = major.getSchoolUuid() + ":" + major.getMajorName();

                            // 检查缓存
                            String cacheKey = userRank + ":" + key + ":" + major.getProvinceName() + ":" + major.getYear();
                            Double cachedResult = probabilityCache.get(cacheKey);
                            if (cachedResult != null) {
                                results.put(key, cachedResult);
                                continue;
                            }

                            // 计算概率
                            Double probability = calculateProbabilityFromGroupedData(
                                userRank, major, groupedHistoryData, groupedPlanData);

                            if (probability != null) {
                                results.put(key, probability);
                                // 缓存结果
                                probabilityCache.put(cacheKey, probability);
                            }
                        } catch (Exception e) {
                            log.warn("多线程计算专业 {} 录取概率失败：{}", major.getMajorName(), e.getMessage());
                        }
                    }
                } catch (Exception e) {
                    log.error("批次 {} 处理失败", batchIndex, e);
                }
            }, probabilityCalculationExecutor);

            futures.add(future);

            // 控制并发数量，避免资源竞争
            if (futures.size() >= MAX_CONCURRENT_TASKS) {
                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
                futures.clear();
            }
        }

        // 等待剩余任务完成
        if (!futures.isEmpty()) {
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        }

        log.info("多线程计算完成，处理了 {} 个批次，获得 {} 个结果", batches.size(), results.size());
        return results;
    }

    /**
     * 单线程计算录取概率（优化版，避免栈溢出）
     */
    private Map<String, Double> calculateProbabilityWithSingleThread(
            List<MajorAdmissionDO> candidateMajors, Integer userRank,
            Map<String, List<MajorAdmissionDO>> groupedHistoryData,
            Map<String, List<CollegeEnrollmentPlanDO>> groupedPlanData) {

        Map<String, Double> results = new HashMap<>();

        // 分批处理，避免一次性处理过多数据
        final int BATCH_SIZE = 500;
        int processedCount = 0;

        for (int i = 0; i < candidateMajors.size(); i += BATCH_SIZE) {
            int endIndex = Math.min(i + BATCH_SIZE, candidateMajors.size());
            List<MajorAdmissionDO> batch = candidateMajors.subList(i, endIndex);

            for (MajorAdmissionDO major : batch) {
                try {
                    String key = major.getSchoolUuid() + ":" + major.getMajorName();

                    // 检查缓存
                    String cacheKey = userRank + ":" + key + ":" + major.getProvinceName() + ":" + major.getYear();
                    Double cachedResult = probabilityCache.get(cacheKey);
                    if (cachedResult != null) {
                        results.put(key, cachedResult);
                        continue;
                    }

                    // 计算概率
                    Double probability = calculateProbabilityFromGroupedData(
                        userRank, major, groupedHistoryData, groupedPlanData);

                    if (probability != null) {
                        results.put(key, probability);
                        // 缓存结果
                        probabilityCache.put(cacheKey, probability);
                    }

                    processedCount++;

                    // 定期检查内存使用情况
                    if (processedCount % 1000 == 0) {
                        if (!BatchQueryOptimizer.isMemoryUsageAcceptable()) {
                            log.warn("内存使用率过高，停止概率计算，已处理：{} 个专业", processedCount);
                            break;
                        }
                    }

                } catch (Exception e) {
                    log.warn("单线程计算专业 {} 录取概率失败：{}", major.getMajorName(), e.getMessage());
                }
            }

            // 批次间短暂休息，释放CPU
            if (i + BATCH_SIZE < candidateMajors.size()) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }

        log.info("单线程计算完成，处理了 {} 个专业，获得 {} 个结果", processedCount, results.size());
        return results;
    }

    /**
     * 迭代式概率计算方法 - 专为大数据量设计，避免栈溢出
     */
    private Map<String, Double> calculateProbabilityWithIterativeMethod(
            List<MajorAdmissionDO> candidateMajors, Integer userRank,
            Map<String, List<MajorAdmissionDO>> groupedHistoryData,
            Map<String, List<CollegeEnrollmentPlanDO>> groupedPlanData) {

        Map<String, Double> results = new HashMap<>();

        log.info("开始迭代式概率计算，候选专业数量：{}", candidateMajors.size());

        int processedCount = 0;
        int successCount = 0;
        long startTime = System.currentTimeMillis();

        try {
            // 使用最简单的for循环，避免任何可能的递归
            for (int i = 0; i < candidateMajors.size(); i++) {
                MajorAdmissionDO major = candidateMajors.get(i);

                try {
                    String key = major.getSchoolUuid() + ":" + major.getMajorName();

                    // 检查缓存
                    String cacheKey = userRank + ":" + key + ":" + major.getProvinceName() + ":" + major.getYear();
                    Double cachedResult = probabilityCache.get(cacheKey);
                    if (cachedResult != null) {
                        results.put(key, cachedResult);
                        successCount++;
                        continue;
                    }

                    // 使用迭代式方法计算概率
                    Double probability = calculateProbabilityIteratively(
                        userRank, major, groupedHistoryData, groupedPlanData);

                    if (probability != null) {
                        results.put(key, probability);
                        // 缓存结果
                        probabilityCache.put(cacheKey, probability);
                        successCount++;
                    }

                } catch (Exception e) {
                    log.debug("计算专业 {} 录取概率失败：{}", major.getMajorName(), e.getMessage());
                }

                processedCount++;

                // 定期输出进度和内存管理
                if (processedCount % 1000 == 0) {
                    long currentTime = System.currentTimeMillis();
                    long elapsed = currentTime - startTime;
                    double avgTime = (double) elapsed / processedCount;

                    log.info("概率计算进度：{}/{} ({:.1f}%), 成功：{}, 平均耗时：{:.2f}ms",
                        processedCount, candidateMajors.size(),
                        (double) processedCount / candidateMajors.size() * 100,
                        successCount, avgTime);

                    // 定期垃圾回收和让出CPU
                    if (processedCount % 5000 == 0) {
                        System.gc();
                        Thread.yield();

                        // 检查内存使用情况
                        Runtime runtime = Runtime.getRuntime();
                        long usedMemory = runtime.totalMemory() - runtime.freeMemory();
                        long maxMemory = runtime.maxMemory();
                        double memoryUsage = (double) usedMemory / maxMemory * 100;

                        log.info("内存使用情况：{:.1f}% ({} MB / {} MB)",
                            memoryUsage, usedMemory / 1024 / 1024, maxMemory / 1024 / 1024);

                        // 如果内存使用过高，暂停一下
                        if (memoryUsage > 85) {
                            log.warn("内存使用率过高，暂停处理");
                            Thread.sleep(1000);
                        }
                    }

                    // 用户体验优化：如果已经处理了足够多的专业且有足够结果，可以提前结束
                    if (processedCount >= 1000 && successCount >= 200) {
                        log.info("已获得足够的推荐结果，提前结束处理以提升响应速度");
                        break;
                    }
                }
            }

        } catch (Exception e) {
            log.error("迭代式概率计算发生异常", e);
        }

        long endTime = System.currentTimeMillis();
        log.info("迭代式概率计算完成，处理：{} 个专业，成功：{} 个，耗时：{} ms",
            processedCount, successCount, endTime - startTime);

        return results;
    }

    /**
     * 从分组数据计算录取概率
     * 这是核心的概率计算逻辑，复用原有的算法但使用预加载的数据
     */
    private Double calculateProbabilityFromGroupedData(
            Integer userRank, MajorAdmissionDO major,
            Map<String, List<MajorAdmissionDO>> groupedHistoryData,
            Map<String, List<CollegeEnrollmentPlanDO>> groupedPlanData) {

        try {
            // 1. 获取该专业的历史录取数据
            String historyKey = major.getSchoolUuid() + ":" + major.getMajorName();
            List<MajorAdmissionDO> historyData = groupedHistoryData.get(historyKey);

            if (historyData == null || historyData.isEmpty()) {
                return null;
            }

            // 2. 获取招生计划数据
            String planKey = major.getSchoolName() + ":" + major.getMajorName();
            List<CollegeEnrollmentPlanDO> planData = groupedPlanData.get(planKey);

            // 3. 计算加权平均位次（考虑招生计划变化）
            List<Integer> adjustedRanks = new ArrayList<>();
            double[] weights = {0.5, 0.3, 0.2}; // 近3年权重

            for (int i = 0; i < historyData.size() && i < weights.length; i++) {
                MajorAdmissionDO data = historyData.get(i);
                if (data.getLowestSection() != null && !data.getLowestSection().isEmpty()) {
                    try {
                        int historicalRank = Integer.parseInt(data.getLowestSection());

                        // 根据招生计划变化调整历史位次
                        int adjustedRank = adjustRankByPlanChange(historicalRank, data, planData, major.getYear());
                        adjustedRanks.add(adjustedRank);
                    } catch (NumberFormatException e) {
                        log.debug("位次数据格式错误：{}", data.getLowestSection());
                    }
                }
            }

            if (adjustedRanks.isEmpty()) {
                return null;
            }

            // 4. 计算加权平均位次
            double weightedAvgRank = 0;
            double totalWeight = 0;
            for (int i = 0; i < adjustedRanks.size() && i < weights.length; i++) {
                weightedAvgRank += adjustedRanks.get(i) * weights[i];
                totalWeight += weights[i];
            }
            weightedAvgRank /= totalWeight;

            // 5. 计算标准差
            double variance = 0;
            for (int rank : adjustedRanks) {
                variance += Math.pow(rank - weightedAvgRank, 2);
            }
            variance /= adjustedRanks.size();
            double stdDev = Math.sqrt(variance);

            // 6. 使用正态分布计算概率
            double zScore = (userRank - weightedAvgRank) / Math.max(stdDev, 1000); // 避免除零
            double baseProbability = normalCDF(-zScore) * 100; // 转换为百分比

            // 7. 应用修正因子
            double finalProbability = baseProbability;

            // 专业热度修正
            if (isHotMajor(major.getMajorName())) {
                finalProbability *= 0.85; // 热门专业降低15%概率
            }

            // 确保概率在0-100范围内
            return Math.max(0, Math.min(100, finalProbability));

        } catch (Exception e) {
            log.debug("计算专业 {} 录取概率时发生异常：{}", major.getMajorName(), e.getMessage());
            return null;
        }
    }

    /**
     * 迭代式概率计算核心方法 - 避免递归调用
     */
    private Double calculateProbabilityIteratively(
            Integer userRank, MajorAdmissionDO major,
            Map<String, List<MajorAdmissionDO>> groupedHistoryData,
            Map<String, List<CollegeEnrollmentPlanDO>> groupedPlanData) {

        try {
            // 1. 获取该专业的历史录取数据
            String historyKey = major.getSchoolUuid() + ":" + major.getMajorName();
            List<MajorAdmissionDO> historyData = groupedHistoryData.get(historyKey);

            if (historyData == null || historyData.isEmpty()) {
                return null;
            }

            // 2. 使用简单的迭代方式处理历史数据
            List<Integer> validRanks = new ArrayList<>();

            // 手动遍历，避免Stream API
            for (MajorAdmissionDO data : historyData) {
                if (data.getLowestSection() != null && !data.getLowestSection().isEmpty()) {
                    try {
                        int rank = Integer.parseInt(data.getLowestSection().trim());
                        if (rank > 0) { // 基本有效性检查
                            validRanks.add(rank);
                        }
                    } catch (NumberFormatException e) {
                        // 忽略无效数据
                    }
                }
            }

            if (validRanks.isEmpty()) {
                return null;
            }

            // 3. 使用简单的算术方法计算概率，避免复杂的数学运算
            // 计算平均位次
            long sum = 0;
            for (Integer rank : validRanks) {
                sum += rank;
            }
            double avgRank = (double) sum / validRanks.size();

            // 计算标准差（简化版本）
            double variance = 0;
            for (Integer rank : validRanks) {
                double diff = rank - avgRank;
                variance += diff * diff;
            }
            variance /= validRanks.size();
            double stdDev = Math.sqrt(variance);

            // 4. 简化的概率计算
            double zScore = (userRank - avgRank) / Math.max(stdDev, 1000);

            // 使用简化的正态分布近似
            double probability;
            if (zScore <= -2) {
                probability = 95.0;
            } else if (zScore <= -1) {
                probability = 85.0;
            } else if (zScore <= 0) {
                probability = 50.0 + (1 - Math.abs(zScore)) * 35.0;
            } else if (zScore <= 1) {
                probability = 50.0 - zScore * 35.0;
            } else if (zScore <= 2) {
                probability = 15.0 - (zScore - 1) * 10.0;
            } else {
                probability = 5.0;
            }

            // 5. 应用简单的修正因子
            // 热门专业修正
            String majorName = major.getMajorName();
            if (majorName != null && (majorName.contains("计算机") || majorName.contains("软件") ||
                majorName.contains("人工智能") || majorName.contains("数据科学"))) {
                probability *= 0.9; // 热门专业降低10%
            }

            // 确保概率在合理范围内
            return Math.max(0, Math.min(100, probability));

        } catch (Exception e) {
            log.debug("迭代式计算专业 {} 录取概率时发生异常：{}", major.getMajorName(), e.getMessage());
            return null;
        }
    }

    @Override
    public String determineRecommendationType(Double probability) {
        if (probability >= 80) {
            return "BAODI";   // 保底：录取概率80%以上
        } else if (probability >= 30) {
            return "WENTUO";  // 稳妥：录取概率30-80%
        } else {
            return "CHONG";   // 冲刺：录取概率10-30%
        }
    }

    @Override
    public String generateRecommendationReason(String schoolName, String majorName, Double probability, 
                                             String type, List<String> tags) {
        StringBuilder reason = new StringBuilder();

        // 1. 学校层次描述
        if (tags != null) {
            if (tags.contains("985")) {
                reason.append("985工程院校，");
            } else if (tags.contains("211")) {
                reason.append("211工程院校，");
            } else if (tags.contains("双一流")) {
                reason.append("双一流建设高校，");
            }
        }

        // 2. 专业实力描述（这里可以根据实际的专业评估数据来完善）
        if (majorName.contains("计算机") || majorName.contains("软件")) {
            reason.append("该专业就业前景良好，");
        }

        // 3. 录取概率描述
        switch (type) {
            case "CHONG":
                reason.append("有一定冲刺可能性");
                break;
            case "WENTUO":
                reason.append("录取概率较高");
                break;
            case "BAODI":
                reason.append("录取把握很大");
                break;
        }

        return reason.toString();
    }

    /**
     * 根据分数计算位次
     */
    private Integer calculateRankByScore(Integer score, String province, Integer year, String examType) {
        try {
            log.debug("开始根据分数计算位次：分数={}, 省份={}, 年份={}, 考试类型={}", score, province, year, examType);

            // 查询一分一段数据
            List<ScoreSegmentDO> segments = scoreSegmentMapper.selectByProvinceYearAndType(province, year.toString(), examType);

            if (segments == null || segments.isEmpty()) {
                log.warn("未找到一分一段数据：省份={}, 年份={}, 考试类型={}", province, year, examType);
                return null;
            }

            // 按分数从高到低排序（确保数据顺序正确）
            segments.sort((a, b) -> {
                try {
                    Integer scoreA = parseScoreFromRange(a.getExaminationScore());
                    Integer scoreB = parseScoreFromRange(b.getExaminationScore());
                    if (scoreA == null && scoreB == null) return 0;
                    if (scoreA == null) return 1;
                    if (scoreB == null) return -1;
                    return scoreB.compareTo(scoreA); // 从高到低排序
                } catch (Exception e) {
                    return 0;
                }
            });

            // 查找用户分数对应的位次
            for (ScoreSegmentDO segment : segments) {
                if (isScoreInRange(score, segment.getExaminationScore())) {
                    Integer rank = parseRankFromRange(segment.getRankingRange());
                    log.debug("找到精确匹配的分数段：{}, 位次范围：{}, 返回位次：{}", segment.getExaminationScore(), segment.getRankingRange(), rank);
                    return rank;
                }
            }

            // 如果没有找到精确匹配，找到第一个分数小于等于用户分数的分数段
            for (ScoreSegmentDO segment : segments) {
                Integer segmentScore = parseScoreFromRange(segment.getExaminationScore());
                if (segmentScore != null && segmentScore <= score) {
                    Integer rank = parseRankFromRange(segment.getRankingRange());
                    log.debug("找到小于等于用户分数的分数段：{}, 位次范围：{}, 返回位次：{}", segment.getExaminationScore(), segment.getRankingRange(), rank);
                    return rank;
                }
            }

            // 如果用户分数高于所有分数段，返回最高分数段的位次
            if (!segments.isEmpty()) {
                ScoreSegmentDO highestSegment = segments.get(0);
                Integer rank = parseRankFromRange(highestSegment.getRankingRange());
                log.debug("用户分数高于所有分数段，返回最高分数段位次范围：{}, 返回位次：{}", highestSegment.getRankingRange(), rank);
                return rank;
            }

        } catch (Exception e) {
            log.error("根据分数计算位次失败：分数={}, 省份={}, 年份={}, 考试类型={}", score, province, year, examType, e);
        }

        return null;
    }

    /**
     * 判断分数是否在指定的分数范围内
     *
     * @param score 用户分数
     * @param scoreRange 分数范围字符串，可能是单一分数（如"650"）或区间（如"650-660"）
     * @return 是否在范围内
     */
    private boolean isScoreInRange(Integer score, String scoreRange) {
        if (score == null || scoreRange == null || scoreRange.trim().isEmpty()) {
            return false;
        }

        try {
            if (scoreRange.contains("-")) {
                // 处理区间分数，如 "650-660"
                String[] parts = scoreRange.split("-");
                if (parts.length == 2) {
                    int minScore = Integer.parseInt(parts[0].trim());
                    int maxScore = Integer.parseInt(parts[1].trim());
                    return score >= minScore && score <= maxScore;
                }
            } else {
                // 处理单一分数，如 "650"
                int segmentScore = Integer.parseInt(scoreRange.trim());
                return score.equals(segmentScore);
            }
        } catch (NumberFormatException e) {
            log.warn("无法解析分数范围：{}", scoreRange);
        }

        return false;
    }

    /**
     * 从分数范围字符串中解析出分数值
     *
     * @param scoreRange 分数范围字符串，可能是单一分数（如"650"）或区间（如"650-660"）
     * @return 解析出的分数值，对于区间返回最高分数
     */
    private Integer parseScoreFromRange(String scoreRange) {
        if (scoreRange == null || scoreRange.trim().isEmpty()) {
            return null;
        }

        try {
            if (scoreRange.contains("-")) {
                // 处理区间分数，如 "650-660"，返回最高分数
                String[] parts = scoreRange.split("-");
                if (parts.length == 2) {
                    return Integer.parseInt(parts[1].trim());
                }
            } else {
                // 处理单一分数，如 "650"
                return Integer.parseInt(scoreRange.trim());
            }
        } catch (NumberFormatException e) {
            log.warn("无法解析分数范围：{}", scoreRange);
        }

        return null;
    }

    /**
     * 从位次范围字符串中解析出最大位次值
     *
     * @param rankingRange 位次范围字符串，格式如"2090-2194"或单一位次"2090"
     * @return 解析出的最大位次值
     */
    private Integer parseRankFromRange(String rankingRange) {
        if (rankingRange == null || rankingRange.trim().isEmpty()) {
            return null;
        }

        try {
            if (rankingRange.contains("-")) {
                // 处理位次区间，如 "2090-2194"，返回最大位次
                String[] parts = rankingRange.split("-");
                if (parts.length == 2) {
                    return Integer.parseInt(parts[1].trim());
                }
            } else {
                // 处理单一位次，如 "2090"
                return Integer.parseInt(rankingRange.trim());
            }
        } catch (NumberFormatException e) {
            log.warn("无法解析位次范围：{}", rankingRange);
        }

        return null;
    }

    /**
     * 根据选科要求筛选专业
     */
    private List<MajorAdmissionDO> filterMajorsBySubjects(List<String> userSubjects, String province,
                                                         Integer year, String examType, String batch) {
        // 获取所有专业录取数据
        List<MajorAdmissionDO> allMajors = majorAdmissionMapper.selectByProvinceAndYear(province, year);

        return allMajors.stream()
                .filter(major -> {
                    // 检查选科要求
                    if (major.getSubjectSelection() != null && !major.getSubjectSelection().isEmpty()) {
                        return SubjectSelectionUtils.checkSubjectMatch(userSubjects, major.getSubjectSelection());
                    }
                    return true; // 没有选科要求的专业都可以报考
                })
                .filter(major -> {
                    // 检查考试类型
                    return examType == null || examType.equals(major.getTypeName());
                })
                .filter(major -> {
                    // 检查录取批次
                    return batch == null || batch.equals(major.getBatchName());
                })
                .collect(Collectors.toList());
    }

    /**
     * 根据招生计划变化调整历史位次
     */
    private int adjustRankByPlanChange(int historicalRank, MajorAdmissionDO historicalData,
                                     List<CollegeEnrollmentPlanDO> planData, Integer currentYear) {
        try {
            // 查找当年和历史年份的招生计划
            Integer currentPlan = null;
            Integer historicalPlan = null;

            for (CollegeEnrollmentPlanDO plan : planData) {
                if (plan.getYear().equals(currentYear)) {
                    currentPlan = parseInteger(plan.getEnrollmentNumbers());
                } else if (plan.getYear().equals(historicalData.getYear())) {
                    historicalPlan = parseInteger(plan.getEnrollmentNumbers());
                }
            }

            if (currentPlan != null && historicalPlan != null && historicalPlan > 0) {
                double planFactor = (double) currentPlan / historicalPlan;
                return (int) (historicalRank * planFactor);
            }
        } catch (Exception e) {
            log.warn("调整历史位次时发生异常：{}", e.getMessage());
        }

        return historicalRank; // 如果无法调整，返回原始位次
    }

    /**
     * 正态分布累积分布函数
     */
    private double normalCDF(double x) {
        return 0.5 * (1 + erf(x / Math.sqrt(2)));
    }

    /**
     * 误差函数近似计算
     */
    private double erf(double x) {
        // 使用近似公式计算误差函数
        double a1 =  0.254829592;
        double a2 = -0.284496736;
        double a3 =  1.421413741;
        double a4 = -1.453152027;
        double a5 =  1.061405429;
        double p  =  0.3275911;

        int sign = x < 0 ? -1 : 1;
        x = Math.abs(x);

        double t = 1.0 / (1.0 + p * x);
        double y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);

        return sign * y;
    }

    /**
     * 判断是否为热门专业
     */
    private boolean isHotMajor(String majorName) {
        List<String> hotMajors = Arrays.asList(
                "计算机科学与技术", "软件工程", "人工智能", "数据科学与大数据技术",
                "临床医学", "金融学", "会计学", "法学"
        );
        return hotMajors.stream().anyMatch(majorName::contains);
    }

    /**
     * 构建推荐项
     */
    private CollegeRecommendItemVO buildRecommendationItem(MajorAdmissionDO major, Double probability,
                                                          String type, CollegeRecommendReqVO reqVO) {
        try {
            // 获取学校信息
            CollegeDO college = collegeMapper.selectBySchoolUuid(major.getSchoolUuid());
            if (college == null) {
                return null;
            }

            // 获取招生计划信息
            CollegeEnrollmentPlanDO plan = collegeEnrollmentPlanMapper.selectBySchoolMajorAndYear(
                    major.getSchoolUuid(), major.getMajorName(), reqVO.getProvince(), reqVO.getYear());

            CollegeRecommendItemVO item = new CollegeRecommendItemVO();

            // 基础信息
            item.setUniversityName(college.getCollegeName());
            item.setRecruitCode(plan != null ? plan.getSpecialCode() : "");
            item.setProvince(college.getProvince());
            item.setCity(college.getCity());
            item.setPropertyName(college.getCollegeProperty());
            item.setCategoryName(college.getCollegeCategory());
            item.setLogo(college.getCoverImage());
            item.setUniversityId(college.getSchoolUuid());
            item.setRanking(college.getRanking());

            // 推荐信息
            item.setType(type);
            item.setEnrollProbability(probability.intValue());
            item.setRecommendationReason(generateRecommendationReason(
                    college.getCollegeName(), major.getMajorName(), probability, type,
                    generateTags(college)));

            // 专业信息
            item.setMajorName(major.getMajorName());
            item.setMajorCode(major.getMajorCode());
            item.setClaim(major.getSubjectSelection());
            item.setBatch(major.getBatchName());

            // 录取数据
            item.setMinScore(parseScore(major.getLowestScore()));
            item.setMinRanks(parseRank(major.getLowestSection()));
            item.setYear(reqVO.getYear());

            // 招生计划
            if (plan != null) {
                item.setPlanNum(parseInteger(plan.getEnrollmentNumbers()));
                item.setStudyCost(plan.getStudyCost());
                item.setStudyYear(plan.getInSchoolYears());
                item.setUniversityMajorGroup(plan.getSpecialGroup());
            }

            // 学校标签
            item.setTags(generateTags(college));

            // 历史数据
            item.setHistoryScore(generateHistoryScore(major.getSchoolUuid(), major.getMajorName(), reqVO.getProvince()));
            item.setParityScore(generateParityScore(major.getSchoolUuid(), major.getMajorName(), reqVO.getProvince(), reqVO.getClassify()));
            item.setHistoryPlanNum(generateHistoryPlanNum(major.getSchoolUuid(), major.getMajorName(), reqVO.getProvince()));

            // 其他信息
            item.setScoreSection(true);
            item.setIndexVip(false);
            item.setNextYear(reqVO.getYear() + 1);
            item.setLevel("本科");
            item.setOriginUniversityName(college.getCollegeName());

            // 生成唯一ID
            item.setZsgkId(generateZsgkId(college.getSchoolUuid()));
            item.setOrcId(generateOrcId(college.getSchoolUuid(), major.getMajorName()));

            return item;

        } catch (Exception e) {
            log.error("构建推荐项时发生异常：{}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 生成学校标签
     */
    private List<String> generateTags(CollegeDO college) {
        List<String> tags = new ArrayList<>();

        if (college.getIs985() != null && college.getIs985()) {
            tags.add("985");
        }
        if (college.getIs211() != null && college.getIs211()) {
            tags.add("211");
        }
        if (college.getIsDualClass() != null && college.getIsDualClass()) {
            tags.add("双一流");
        }

        // 添加学院标签
        if (college.getCollegeTags() != null && !college.getCollegeTags().isEmpty()) {
            tags.addAll(college.getCollegeTags());
        }

        return tags;
    }

    /**
     * 生成历史分数数据
     */
    private String generateHistoryScore(String schoolUuid, String majorName, String province) {
        try {
            List<MajorAdmissionDO> historyData = majorAdmissionMapper.selectBySchoolAndMajor(
                    schoolUuid, majorName, province, Arrays.asList(2022, 2023, 2024));

            List<Map<String, String>> historyList = new ArrayList<>();
            for (MajorAdmissionDO data : historyData) {
                Map<String, String> yearData = new HashMap<>();
                String value = String.format("%s,%s,%s",
                        data.getLowestScore() != null ? data.getLowestScore() : "0",
                        data.getLowestSection() != null ? data.getLowestSection() : "0",
                        "0" // 招生计划数，需要从招生计划表获取
                );
                yearData.put(data.getYear().toString(), value);
                historyList.add(yearData);
            }

            return JsonUtils.toJsonString(historyList);
        } catch (Exception e) {
            log.warn("生成历史分数数据失败：{}", e.getMessage());
            return "[]";
        }
    }

    /**
     * 生成等位分数据
     */
    private String generateParityScore(String schoolUuid, String majorName, String province, String examType) {
        try {
            List<MajorAdmissionDO> historyData = majorAdmissionMapper.selectBySchoolAndMajor(
                    schoolUuid, majorName, province, Arrays.asList(2022, 2023, 2024));

            List<Map<String, String>> parityList = new ArrayList<>();
            for (MajorAdmissionDO data : historyData) {
                if (data.getLowestSection() != null && !data.getLowestSection().isEmpty()) {
                    try {
                        int rank = Integer.parseInt(data.getLowestSection());
                        int equivalentScore = convertRankToScore(rank, province, data.getYear(), examType);

                        Map<String, String> yearData = new HashMap<>();
                        yearData.put(data.getYear().toString(), String.valueOf(equivalentScore));
                        parityList.add(yearData);
                    } catch (NumberFormatException e) {
                        log.warn("位次数据格式错误：{}", data.getLowestSection());
                    }
                }
            }

            return JsonUtils.toJsonString(parityList);
        } catch (Exception e) {
            log.warn("生成等位分数据失败：{}", e.getMessage());
            return "[]";
        }
    }

    /**
     * 生成历史招生计划数据
     */
    private String generateHistoryPlanNum(String schoolUuid, String majorName, String province) {
        try {
            List<CollegeEnrollmentPlanDO> planData = collegeEnrollmentPlanMapper.selectBySchoolAndMajor(
                    schoolUuid, majorName, province, Arrays.asList(2022, 2023, 2024));

            List<Map<String, Integer>> planList = new ArrayList<>();
            for (CollegeEnrollmentPlanDO plan : planData) {
                Map<String, Integer> yearPlan = new HashMap<>();
                yearPlan.put(plan.getYear().toString(), parseInteger(plan.getEnrollmentNumbers()));
                planList.add(yearPlan);
            }

            return JsonUtils.toJsonString(planList);
        } catch (Exception e) {
            log.warn("生成历史招生计划数据失败：{}", e.getMessage());
            return "[]";
        }
    }

    /**
     * 将位次转换为等位分
     */
    private int convertRankToScore(int rank, String province, Integer year, String examType) {
        try {
            List<ScoreSegmentDO> segments = scoreSegmentMapper.selectByProvinceYearAndType(province, year.toString(), examType);
            for (ScoreSegmentDO segment : segments) {
                if (segment.getTotalCandidates() >= rank) {
                    return Integer.parseInt(segment.getExaminationScore());
                }
            }
        } catch (Exception e) {
            log.warn("位次转换分数失败：{}", e.getMessage());
        }
        return 0;
    }

    /**
     * 解析分数字符串
     */
    private Integer parseScore(String scoreStr) {
        if (scoreStr == null || scoreStr.isEmpty() || "-".equals(scoreStr)) {
            return 0;
        }
        try {
            return Integer.parseInt(scoreStr);
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    /**
     * 解析位次字符串
     */
    private Integer parseRank(String rankStr) {
        if (rankStr == null || rankStr.isEmpty() || "-".equals(rankStr)) {
            return 0;
        }
        try {
            return Integer.parseInt(rankStr);
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    /**
     * 解析整数字符串
     */
    private Integer parseInteger(String intStr) {
        if (intStr == null || intStr.isEmpty() || "-".equals(intStr)) {
            return 0;
        }
        try {
            return Integer.parseInt(intStr);
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    /**
     * 生成掌上高考ID
     */
    private Long generateZsgkId(String schoolUuid) {
        return (long) Math.abs(schoolUuid.hashCode());
    }

    /**
     * 生成推荐记录ID
     */
    private Long generateOrcId(String schoolUuid, String majorName) {
        return (long) Math.abs((schoolUuid + majorName).hashCode());
    }

    /**
     * 应用用户偏好过滤
     */
    private List<CollegeRecommendItemVO> applyPreferences(List<CollegeRecommendItemVO> recommendations,
                                                         CollegeRecommendReqVO.PreferencesVO preferences) {
        return recommendations.stream()
                .filter(item -> {
                    // 地域偏好过滤
                    if (preferences.getRegions() != null && !preferences.getRegions().isEmpty()) {
                        if (!preferences.getRegions().contains(item.getProvince())) {
                            return false;
                        }
                    }

                    // 学校类型偏好过滤
                    if (preferences.getSchoolTypes() != null && !preferences.getSchoolTypes().isEmpty()) {
                        boolean hasMatchingType = false;
                        for (String preferredType : preferences.getSchoolTypes()) {
                            if (item.getTags() != null && item.getTags().contains(preferredType)) {
                                hasMatchingType = true;
                                break;
                            }
                        }
                        if (!hasMatchingType) {
                            return false;
                        }
                    }

                    return true;
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取推荐类型排序权重
     */
    private int getTypeOrder(String type) {
        switch (type) {
            case "BAODI":
                return 1;
            case "WENTUO":
                return 2;
            case "CHONG":
                return 3;
            default:
                return 4;
        }
    }

    /**
     * 保存推荐记录
     */
    private void saveRecommendationRecords(Long userId, List<CollegeRecommendItemVO> recommendations,
                                         CollegeRecommendReqVO reqVO) {
        try {
            LocalDateTime now = LocalDateTime.now();

            for (CollegeRecommendItemVO item : recommendations) {
                // 检查是否已存在相同的推荐记录
                if (!collegeRecommendationMapper.existsSameRecommendation(userId, item.getUniversityId(),
                        item.getMajorName(), reqVO.getScore(), reqVO.getRanks())) {

                    CollegeRecommendationDO record = CollegeRecommendationDO.builder()
                            .userId(userId)
                            .recommendationTime(now)
                            .recommendationType(item.getType())
                            .schoolUuid(item.getUniversityId())
                            .schoolName(item.getUniversityName())
                            .majorName(item.getMajorName())
                            .admissionProbability(BigDecimal.valueOf(item.getEnrollProbability()))
                            .recommendationReason(item.getRecommendationReason())
                            .userScore(reqVO.getScore())
                            .userRank(reqVO.getRanks())
                            .userProvince(reqVO.getProvince())
                            .userSubjectCombination(reqVO.getSubjects())
                            .historyScore(item.getHistoryScore())
                            .parityScore(item.getParityScore())
                            .historyPlanNum(item.getHistoryPlanNum())
                            .tags(JsonUtils.toJsonString(item.getTags()))
                            .careerDirection(item.getCareerDirection())
                            .majorLevel(item.getMajorLevel())
                            .build();

                    collegeRecommendationMapper.insert(record);
                }
            }
        } catch (Exception e) {
            log.error("保存推荐记录失败：{}", e.getMessage(), e);
        }
    }

    /**
     * 构建响应结果
     */
    private CollegeRecommendRespVO buildResponse(List<CollegeRecommendItemVO> pageList,
                                               CollegeRecommendReqVO reqVO, int total,
                                               int chongCount, int wentuoCount, int baodiCount,
                                               Integer userRank) {
        CollegeRecommendRespVO respVO = new CollegeRecommendRespVO();

        // 分页信息
        respVO.setTotal((long) total);
        respVO.setList(pageList);
        respVO.setPageNum(reqVO.getPageNum());
        respVO.setPageSize(reqVO.getPageSize());
        respVO.setSize(pageList.size());
        respVO.setStartRow((reqVO.getPageNum() - 1) * reqVO.getPageSize() + 1);
        respVO.setEndRow(respVO.getStartRow() + pageList.size() - 1);
        respVO.setPages((int) Math.ceil((double) total / reqVO.getPageSize()));
        respVO.setPrePage(reqVO.getPageNum() > 1 ? reqVO.getPageNum() - 1 : 0);
        respVO.setNextPage(reqVO.getPageNum() < respVO.getPages() ? reqVO.getPageNum() + 1 : 0);
        respVO.setIsFirstPage(reqVO.getPageNum() == 1);
        respVO.setIsLastPage(reqVO.getPageNum().equals(respVO.getPages()));
        respVO.setHasPreviousPage(reqVO.getPageNum() > 1);
        respVO.setHasNextPage(reqVO.getPageNum() < respVO.getPages());
        respVO.setNavigatePages(8);

        // 导航页码
        List<Integer> navigatePageNums = new ArrayList<>();
        int start = Math.max(1, reqVO.getPageNum() - 4);
        int end = Math.min(respVO.getPages(), start + 7);
        for (int i = start; i <= end; i++) {
            navigatePageNums.add(i);
        }
        respVO.setNavigatepageNums(navigatePageNums);
        respVO.setNavigateFirstPage(navigatePageNums.isEmpty() ? 0 : navigatePageNums.get(0));
        respVO.setNavigateLastPage(navigatePageNums.isEmpty() ? 0 : navigatePageNums.get(navigatePageNums.size() - 1));

        // 汇总信息
        CollegeRecommendRespVO.SummaryVO summary = new CollegeRecommendRespVO.SummaryVO();
        summary.setUserScore(reqVO.getScore());
        summary.setUserRank(userRank);
        summary.setProvince(reqVO.getProvince());
        summary.setExamType(reqVO.getClassify() + "类");
        summary.setSubjectCombination(reqVO.getSubjects().replace(",", "+"));
        summary.setChongCount(chongCount);
        summary.setWentuoCount(wentuoCount);
        summary.setBaodiCount(baodiCount);
        summary.setAnalysisText(String.format("基于您的分数%d分，位次%d名，为您推荐%d所院校",
                reqVO.getScore(), userRank != null ? userRank : 0, total));
        respVO.setSummary(summary);

        return respVO;
    }

    /**
     * 清理概率缓存
     * 定期清理缓存，避免内存泄漏
     */
    public void clearProbabilityCache() {
        probabilityCache.clear();
        batchDataCache.clear();
        log.info("已清理录取概率缓存");
    }

    /**
     * 获取缓存统计信息
     */
    public Map<String, Object> getCacheStats() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("probabilityCacheSize", probabilityCache.size());
        stats.put("batchDataCacheSize", batchDataCache.size());
        stats.put("threadPoolActiveCount", ((ThreadPoolExecutor) probabilityCalculationExecutor).getActiveCount());
        stats.put("threadPoolQueueSize", ((ThreadPoolExecutor) probabilityCalculationExecutor).getQueue().size());
        return stats;
    }

    /**
     * 超级分批查询 - 处理超大数据量，避免StackOverflowError
     */
    private List<MajorAdmissionDO> performSuperBatchQuery(
            List<String> schoolUuids, List<String> majorNames,
            List<Integer> years, String examType, String province) {

        List<MajorAdmissionDO> allResults = new ArrayList<>();

        // 超小批次处理，避免SQL过于复杂
        final int SUPER_BATCH_SIZE = 20; // 极小批次，确保稳定性

        try {
            // 按学校UUID分批
            for (int i = 0; i < schoolUuids.size(); i += SUPER_BATCH_SIZE) {
                int endIndex = Math.min(i + SUPER_BATCH_SIZE, schoolUuids.size());
                List<String> batchSchoolUuids = schoolUuids.subList(i, endIndex);

                // 按专业名称分批
                for (int j = 0; j < majorNames.size(); j += SUPER_BATCH_SIZE) {
                    int majorEndIndex = Math.min(j + SUPER_BATCH_SIZE, majorNames.size());
                    List<String> batchMajorNames = majorNames.subList(j, majorEndIndex);

                    // 按年份查询
                    for (Integer queryYear : years) {
                        try {
                            List<MajorAdmissionDO> batchData = majorAdmissionMapper
                                .batchSelectAdmissionScoresSimple(batchSchoolUuids, batchMajorNames,
                                    queryYear, examType, province);
                            allResults.addAll(batchData);

                            // 添加短暂延迟，避免数据库压力过大
                            if (allResults.size() % 1000 == 0) {
                                Thread.sleep(10);
                            }
                        } catch (Exception e) {
                            log.warn("超级分批查询失败 - 学校批次[{}-{}], 专业批次[{}-{}], 年份{}: {}",
                                i, endIndex-1, j, majorEndIndex-1, queryYear, e.getMessage());
                        }
                    }
                }

                log.debug("完成学校批次 [{}-{}] 的查询，当前总数据量：{}", i, endIndex-1, allResults.size());
            }

        } catch (Exception e) {
            log.error("超级分批查询发生异常", e);
        }

        // 去重处理
        Map<String, MajorAdmissionDO> uniqueResults = new LinkedHashMap<>();
        for (MajorAdmissionDO data : allResults) {
            String key = data.getSchoolUuid() + ":" + data.getMajorName() + ":" + data.getYear();
            uniqueResults.put(key, data);
        }

        log.info("超级分批查询完成，原始数据：{} 条，去重后：{} 条",
            allResults.size(), uniqueResults.size());

        return new ArrayList<>(uniqueResults.values());
    }

    /**
     * 正常批量查询
     */
    private List<MajorAdmissionDO> performNormalBatchQuery(
            List<String> schoolUuids, List<String> majorNames,
            List<Integer> years, String examType, String province) {

        List<MajorAdmissionDO> allHistoryData = new ArrayList<>();

        for (Integer queryYear : years) {
            try {
                List<MajorAdmissionDO> yearData = majorAdmissionMapper.batchSelectAdmissionScores(
                    schoolUuids, majorNames, queryYear, examType, province);
                allHistoryData.addAll(yearData);
            } catch (Exception e) {
                log.warn("正常批量查询{}年录取数据失败：{}", queryYear, e.getMessage());
                // 失败时使用降级查询
                List<MajorAdmissionDO> fallbackData = performFallbackQuery(
                    schoolUuids, majorNames, queryYear, examType, province);
                allHistoryData.addAll(fallbackData);
            }
        }

        return allHistoryData;
    }

    /**
     * 降级查询 - 当批量查询失败时的备用方案
     */
    private List<MajorAdmissionDO> performFallbackQuery(
            List<String> schoolUuids, List<String> majorNames,
            Integer year, String examType, String province) {

        List<MajorAdmissionDO> results = new ArrayList<>();

        try {
            // 使用最简单的查询方式
            LambdaQueryWrapperX<MajorAdmissionDO> wrapper = new LambdaQueryWrapperX<MajorAdmissionDO>()
                .eq(MajorAdmissionDO::getYear, year)
                .eq(MajorAdmissionDO::getProvinceName, province);

            if (examType != null && !examType.isEmpty()) {
                wrapper.eq(MajorAdmissionDO::getTypeName, examType);
            }

            // 分批添加学校条件
            final int FALLBACK_BATCH_SIZE = 100;
            for (int i = 0; i < schoolUuids.size(); i += FALLBACK_BATCH_SIZE) {
                int endIndex = Math.min(i + FALLBACK_BATCH_SIZE, schoolUuids.size());
                List<String> batchUuids = schoolUuids.subList(i, endIndex);

                LambdaQueryWrapperX<MajorAdmissionDO> batchWrapper = new LambdaQueryWrapperX<MajorAdmissionDO>()
                    .eq(MajorAdmissionDO::getYear, year)
                    .eq(MajorAdmissionDO::getProvinceName, province)
                    .in(MajorAdmissionDO::getSchoolUuid, batchUuids);

                if (examType != null && !examType.isEmpty()) {
                    batchWrapper.eq(MajorAdmissionDO::getTypeName, examType);
                }

                List<MajorAdmissionDO> batchResults = majorAdmissionMapper.selectList(batchWrapper);

                // 在内存中过滤专业名称
                List<MajorAdmissionDO> filteredResults = batchResults.stream()
                    .filter(data -> majorNames.stream().anyMatch(majorName ->
                        data.getMajorName() != null &&
                        (data.getMajorName().contains(majorName) || majorName.contains(data.getMajorName()))))
                    .collect(Collectors.toList());

                results.addAll(filteredResults);
            }

            log.info("降级查询完成，获得数据：{} 条", results.size());

        } catch (Exception e) {
            log.error("降级查询也失败了", e);
        }

        return results;
    }

    /**
     * 极简查询策略 - 处理超大数据量时的最后手段
     */
    private List<MajorAdmissionDO> performUltraSimpleQuery(
            List<String> schoolUuids, List<String> majorNames,
            List<Integer> years, String examType, String province) {

        List<MajorAdmissionDO> results = new ArrayList<>();

        try {
            log.info("开始极简查询，将只查询基础条件，后续在内存中过滤");

            // 只使用最基础的查询条件
            for (Integer year : years) {
                LambdaQueryWrapperX<MajorAdmissionDO> wrapper = new LambdaQueryWrapperX<MajorAdmissionDO>()
                    .eq(MajorAdmissionDO::getYear, year)
                    .eq(MajorAdmissionDO::getProvinceName, province);

                if (examType != null && !examType.isEmpty()) {
                    wrapper.eq(MajorAdmissionDO::getTypeName, examType);
                }

                // 限制查询结果数量，避免内存溢出
                wrapper.last("LIMIT 50000");

                List<MajorAdmissionDO> yearResults = majorAdmissionMapper.selectList(wrapper);

                // 在内存中过滤学校和专业
                List<MajorAdmissionDO> filteredResults = yearResults.stream()
                    .filter(data -> schoolUuids.contains(data.getSchoolUuid()))
                    .filter(data -> majorNames.stream().anyMatch(majorName ->
                        data.getMajorName() != null &&
                        (data.getMajorName().contains(majorName) || majorName.contains(data.getMajorName()))))
                    .collect(Collectors.toList());

                results.addAll(filteredResults);

                log.info("极简查询{}年完成，原始数据：{}条，过滤后：{}条",
                    year, yearResults.size(), filteredResults.size());
            }

        } catch (Exception e) {
            log.error("极简查询失败", e);
        }

        log.info("极简查询总计完成，获得数据：{} 条", results.size());
        return results;
    }

    /**
     * 历史数据采样 - 减少数据量避免栈溢出
     */
    private List<MajorAdmissionDO> sampleHistoryData(
            List<MajorAdmissionDO> allHistoryData,
            List<MajorAdmissionDO> candidateMajors,
            int maxSize) {

        try {
            // 创建候选专业的索引
            Set<String> candidateKeys = candidateMajors.stream()
                .map(major -> major.getSchoolUuid() + ":" + major.getMajorName())
                .collect(Collectors.toSet());

            // 优先保留候选专业相关的历史数据
            List<MajorAdmissionDO> priorityData = new ArrayList<>();
            List<MajorAdmissionDO> otherData = new ArrayList<>();

            for (MajorAdmissionDO data : allHistoryData) {
                String key = data.getSchoolUuid() + ":" + data.getMajorName();
                if (candidateKeys.contains(key)) {
                    priorityData.add(data);
                } else {
                    otherData.add(data);
                }
            }

            // 构建采样结果
            List<MajorAdmissionDO> sampledData = new ArrayList<>();

            // 优先添加候选专业相关数据
            int priorityLimit = Math.min(priorityData.size(), maxSize * 2 / 3);
            sampledData.addAll(priorityData.subList(0, priorityLimit));

            // 添加其他数据
            int remainingSpace = maxSize - sampledData.size();
            if (remainingSpace > 0 && !otherData.isEmpty()) {
                int otherLimit = Math.min(otherData.size(), remainingSpace);
                sampledData.addAll(otherData.subList(0, otherLimit));
            }

            log.info("数据采样完成 - 原始：{}条，优先：{}条，其他：{}条，最终：{}条",
                allHistoryData.size(), priorityLimit, Math.min(otherData.size(), remainingSpace), sampledData.size());

            return sampledData;

        } catch (Exception e) {
            log.error("数据采样失败，返回截断数据", e);
            return allHistoryData.subList(0, Math.min(allHistoryData.size(), maxSize));
        }
    }

    /**
     * 迭代式分组历史数据 - 完全避免递归和Stream API
     */
    private Map<String, List<MajorAdmissionDO>> iterativeGroupHistoryData(List<MajorAdmissionDO> allHistoryData) {
        Map<String, List<MajorAdmissionDO>> groupedData = new HashMap<>();

        log.info("开始迭代式分组历史数据，数据量：{} 条", allHistoryData.size());

        try {
            // 使用简单的for循环，避免任何递归操作
            int processedCount = 0;
            for (MajorAdmissionDO data : allHistoryData) {
                if (data != null && data.getSchoolUuid() != null && data.getMajorName() != null) {
                    String key = data.getSchoolUuid() + ":" + data.getMajorName();

                    // 手动处理分组，避免computeIfAbsent的潜在递归
                    List<MajorAdmissionDO> group = groupedData.get(key);
                    if (group == null) {
                        group = new ArrayList<>();
                        groupedData.put(key, group);
                    }
                    group.add(data);
                }

                processedCount++;

                // 定期输出进度，避免长时间无响应
                if (processedCount % 10000 == 0) {
                    log.debug("已处理历史数据：{} / {}", processedCount, allHistoryData.size());

                    // 主动触发垃圾回收，释放内存
                    if (processedCount % 50000 == 0) {
                        System.gc();
                        Thread.yield(); // 让出CPU时间
                    }
                }
            }

            log.info("迭代式分组历史数据完成，分组数：{}", groupedData.size());

        } catch (Exception e) {
            log.error("迭代式分组历史数据失败", e);
        }

        return groupedData;
    }

    /**
     * 迭代式分组招生计划数据 - 完全避免递归
     */
    private Map<String, List<CollegeEnrollmentPlanDO>> iterativeGroupPlanData(List<CollegeEnrollmentPlanDO> allPlanData) {
        Map<String, List<CollegeEnrollmentPlanDO>> groupedData = new HashMap<>();

        log.info("开始迭代式分组招生计划数据，数据量：{} 条", allPlanData.size());

        try {
            // 使用简单的for循环
            for (CollegeEnrollmentPlanDO plan : allPlanData) {
                if (plan != null && plan.getSchoolName() != null && plan.getCollegeMajorName() != null) {
                    String key = plan.getSchoolName() + ":" + plan.getCollegeMajorName();

                    // 手动处理分组
                    List<CollegeEnrollmentPlanDO> group = groupedData.get(key);
                    if (group == null) {
                        group = new ArrayList<>();
                        groupedData.put(key, group);
                    }
                    group.add(plan);
                }
            }

            log.info("迭代式分组招生计划数据完成，分组数：{}", groupedData.size());

        } catch (Exception e) {
            log.error("迭代式分组招生计划数据失败", e);
        }

        return groupedData;
    }

    /**
     * 智能优先级处理专业 - 优先处理最相关的专业，提升用户体验
     */
    private List<MajorAdmissionDO> prioritizeMajorsForProcessing(
            List<MajorAdmissionDO> candidateMajors, Integer userRank,
            Integer pageNum, Integer pageSize) {

        if (candidateMajors == null || candidateMajors.isEmpty()) {
            return new ArrayList<>();
        }

        log.info("开始专业优先级处理，总专业数：{}，页码：{}，页面大小：{}",
            candidateMajors.size(), pageNum, pageSize);

        try {
            // 1. 计算每个专业的优先级分数
            List<MajorWithPriority> majorsWithPriority = new ArrayList<>();

            for (MajorAdmissionDO major : candidateMajors) {
                double priorityScore = calculateMajorPriorityScore(major, userRank);
                majorsWithPriority.add(new MajorWithPriority(major, priorityScore));
            }

            // 2. 按优先级分数排序（降序）
            majorsWithPriority.sort((a, b) -> Double.compare(b.priorityScore, a.priorityScore));

            // 3. 计算需要处理的专业范围
            int totalMajors = majorsWithPriority.size();
            int startIndex = (pageNum - 1) * pageSize;
            int endIndex = Math.min(startIndex + pageSize * 3, totalMajors); // 多处理2页的数据，提供更多选择

            // 确保至少处理一页数据
            if (startIndex >= totalMajors) {
                startIndex = Math.max(0, totalMajors - pageSize);
                endIndex = totalMajors;
            }

            // 4. 提取优先处理的专业
            List<MajorAdmissionDO> prioritizedMajors = new ArrayList<>();
            for (int i = startIndex; i < endIndex; i++) {
                prioritizedMajors.add(majorsWithPriority.get(i).major);
            }

            log.info("优先级处理完成，处理范围：[{}, {}]，优先处理专业数：{}",
                startIndex, endIndex - 1, prioritizedMajors.size());

            return prioritizedMajors;

        } catch (Exception e) {
            log.error("专业优先级处理失败，返回原始列表", e);
            return candidateMajors;
        }
    }

    /**
     * 计算专业优先级分数
     */
    private double calculateMajorPriorityScore(MajorAdmissionDO major, Integer userRank) {
        double score = 0.0;

        try {
            // 1. 基于历史录取位次的匹配度（权重40%）
            if (major.getLowestSection() != null && !major.getLowestSection().isEmpty()) {
                try {
                    int historicalRank = Integer.parseInt(major.getLowestSection().trim());
                    if (historicalRank > 0) {
                        // 计算位次匹配度，越接近用户位次分数越高
                        double rankDiff = Math.abs(userRank - historicalRank);
                        double maxRankDiff = Math.max(userRank, historicalRank);
                        double rankMatchScore = Math.max(0, 1 - (rankDiff / maxRankDiff));
                        score += rankMatchScore * 40;
                    }
                } catch (NumberFormatException e) {
                    // 忽略无效数据
                }
            }

            // 2. 学校层次分数（权重30%）
            String schoolName = major.getSchoolName();
            if (schoolName != null) {
                if (schoolName.contains("985") || schoolName.contains("清华") || schoolName.contains("北大")) {
                    score += 30;
                } else if (schoolName.contains("211") || schoolName.contains("双一流")) {
                    score += 25;
                } else if (schoolName.contains("大学")) {
                    score += 20;
                } else {
                    score += 15;
                }
            }

            // 3. 专业热度分数（权重20%）
            String majorName = major.getMajorName();
            if (majorName != null) {
                if (majorName.contains("计算机") || majorName.contains("软件") || majorName.contains("人工智能")) {
                    score += 20; // 热门专业
                } else if (majorName.contains("医学") || majorName.contains("金融") || majorName.contains("法学")) {
                    score += 18;
                } else if (majorName.contains("工程") || majorName.contains("管理")) {
                    score += 15;
                } else {
                    score += 10;
                }
            }

            // 4. 地理位置分数（权重10%）
            String provinceName = major.getProvinceName();
            if (provinceName != null) {
                if (provinceName.contains("北京") || provinceName.contains("上海") || provinceName.contains("深圳")) {
                    score += 10; // 一线城市
                } else if (provinceName.contains("广东") || provinceName.contains("江苏") || provinceName.contains("浙江")) {
                    score += 8; // 发达省份
                } else {
                    score += 5;
                }
            }

        } catch (Exception e) {
            log.debug("计算专业优先级分数失败：{}", e.getMessage());
            score = 50; // 默认分数
        }

        return score;
    }

    /**
     * 专业优先级包装类
     */
    private static class MajorWithPriority {
        final MajorAdmissionDO major;
        final double priorityScore;

        MajorWithPriority(MajorAdmissionDO major, double priorityScore) {
            this.major = major;
            this.priorityScore = priorityScore;
        }
    }

    /**
     * 优雅关闭线程池
     */
    public void shutdown() {
        try {
            probabilityCalculationExecutor.shutdown();
            if (!probabilityCalculationExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                probabilityCalculationExecutor.shutdownNow();
                log.warn("录取概率计算线程池强制关闭");
            } else {
                log.info("录取概率计算线程池正常关闭");
            }
        } catch (InterruptedException e) {
            probabilityCalculationExecutor.shutdownNow();
            Thread.currentThread().interrupt();
            log.error("关闭线程池时被中断", e);
        }
    }
}
